package inge_soft.gestoriusNuevo.business.controller.implementation;

import inge_soft.gestoriusNuevo.business.logic.abstraction.IParserExcepciones;
import inge_soft.gestoriusNuevo.business.service.abstraction.IUsuarioService;
import inge_soft.gestoriusNuevo.persistence.entity.implementation.Documento;
import inge_soft.gestoriusNuevo.persistence.entity.implementation.Domicilio;
import inge_soft.gestoriusNuevo.persistence.entity.implementation.Localidad;
import inge_soft.gestoriusNuevo.persistence.entity.implementation.Pais;
import inge_soft.gestoriusNuevo.persistence.entity.implementation.TipoDocumento;
import inge_soft.gestoriusNuevo.persistence.entity.implementation.Usuario;
import inge_soft.gestoriusNuevo.persistence.entity.implementation.UsuarioRegistrado;

import java.util.ArrayList;
import java.util.List;

import org.springframework.dao.DataIntegrityViolationException;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.KeyEvent;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.VariableResolver;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import org.zkoss.zul.Button;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Label;
import org.zkoss.zul.ListModel;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Window;

@VariableResolver(org.zkoss.zkplus.spring.DelegatingVariableResolver.class)
public class FormularioRegistracionMVC extends SelectorComposer<Window> {

	private static final long serialVersionUID = 3158696617511800888L;
	private static final int LONGITUD_MINIMA_NOMBRE_USUARIO = 5;
	private static final int LONGITUD_MINIMA_CONTRASENIA = 5;

	@WireVariable("usuarioService")
	IUsuarioService usuarioService;
	
	@WireVariable("parserExcepcionesUsuario")
	IParserExcepciones parserExcepciones;
	
	@Wire
	private Textbox textBoxNombreUsuario;
	@Wire
	private Label labelErrorNombreUsuario;
	@Wire
	private Textbox textBoxContrasenia;
	@Wire
	private Label labelErrorContrasenia;
	@Wire
	private Textbox textBoxContraseniaRepetida;
	@Wire
	private Label labelErrorContraseniaRepetida;
	@Wire
	private Textbox textBoxNombre;
	@Wire
	private Label labelErrorNombre;
	@Wire
	private Textbox textBoxApellido;
	@Wire
	private Label labelErrorApellido;
	@Wire
	private Combobox comboboxTipoDocumento;
	@Wire
	private Label labelErrorTipoDocumento;
	@Wire
	private Textbox textBoxNumeroDocumento;
	@Wire
	private Label labelErrorNumeroDocumento;
	@Wire
	private Textbox textBoxMail;
	@Wire
	private Label labelErrorMail;
	@Wire
	private Textbox textBoxMailAlternativo;
	@Wire
	private Label labelErrorMailAlternativo;
	@Wire
	private Textbox textBoxTelefonoContacto;
	@Wire
	private Label labelErrorTelefonoContacto;
	@Wire
	private Combobox comboBoxNacionalidad;
	@Wire
	private Label labelErrorNacionalidad;
	@Wire
	private Combobox comboBoxPaisResidencia;
	@Wire
	private Label labelErrorPaisResidencia;
	@Wire
	private Combobox comboBoxLocalidadResidencia;
	@Wire
	private Label labelErrorLocalidadResidencia;
	@Wire
	private Textbox textBoxCalle;
	@Wire
	private Label labelErrorCalle;
	@Wire
	private Textbox textBoxAltura;
	@Wire
	private Label labelErrorAltura;
	@Wire
	private Textbox textBoxDepto;
	@Wire
	private Label labelErrorDepto;
	@Wire
	private Textbox textBoxPiso;
	@Wire
	private Label labelErrorPiso;
	@Wire
	private Label labelErroresAlUsuario;
	@Wire
	private Button botonRegistrarse;

	private List<TipoDocumento> listaTiposDocumento;

	private List<Pais> listaPaises;

	private List<Pais> listaNacionalidades;

	private List<Localidad> listaLocalidades;

	public void doAfterCompose(Window comp) throws Exception {
		hacerAntesDeCablearVariables();
		super.doAfterCompose(comp); // wire variables and event listners
		hacerDespuesDeCablearVariables();
	}

	private void hacerAntesDeCablearVariables() {
		//cargo listas fijas
		listaTiposDocumento = usuarioService.obtenerTodosTiposDocumentoOrdenadosPorNombreAscendente();
		listaPaises = usuarioService.obtenerTodosLosPaisesOrdenadosPorNombreAscendente();
		listaNacionalidades = usuarioService.obtenerTodosLosPaisesOrdenadosPorNombreNacionalidadAscendente();
	}

	private void hacerDespuesDeCablearVariables() {
		// setear modelos fijos
		comboboxTipoDocumento.setModel(getTiposDocumento());
		comboBoxNacionalidad.setModel(getNacionalidades());
		comboBoxPaisResidencia.setModel(getPaises());
		// contruyo listas "vivas"
		listaLocalidades = new ArrayList<Localidad>();

		// seteo listener a combobox localidades
		comboBoxLocalidadResidencia.addEventListener(Events.ON_OK, new EventListener<KeyEvent>() { // on cancel, segun documentacion, es cuando tocaron una tecla

			public void onEvent(KeyEvent event) throws Exception {
				String cadenaIngresada = comboBoxLocalidadResidencia.getText();
				if (cadenaIngresada.isEmpty()) {
					listaLocalidades.clear();
					return;
				}
				listaLocalidades.clear();
				Pais paisSeleccionado = getPaisSeleccionado();
				listaLocalidades.addAll(
						usuarioService.obtenerLasLocalidadesDePaisQueCoincidanConNombreOrdenadasPorNombreAscendente(paisSeleccionado, cadenaIngresada)
						);
				comboBoxLocalidadResidencia.setModel(new ListModelList<Localidad>(listaLocalidades));
			}
		});
	}

	public ListModel<TipoDocumento> getTiposDocumento() {
		return new ListModelList<TipoDocumento>(listaTiposDocumento);
	}

	public ListModel<Pais> getNacionalidades() {
		return new ListModelList<Pais>(listaNacionalidades);
	}

	public ListModel<Pais> getPaises() {
		return new ListModelList<Pais>(listaPaises);
	}

	public ListModel<Localidad> getLocalidades() {
		return new ListModelList<Localidad>(listaLocalidades);
	}

	private Pais getPaisSeleccionado() {
		int posicion = comboBoxPaisResidencia.getSelectedIndex();
		if (posicion < 0) {
			return null;
		}
		return listaPaises.get(posicion);
	}

	public boolean validar() {
		boolean devolver = true; // para que corrija todo "de un saque"
		// valido el nombre de usuario, que no sea vacio ni menor que la longitud minima
		if (textBoxNombreUsuario.getText().isEmpty() || textBoxNombreUsuario.getText().length() < LONGITUD_MINIMA_NOMBRE_USUARIO) {
			labelErrorNombreUsuario.setValue("El nombre de usuario debe tener "+ LONGITUD_MINIMA_NOMBRE_USUARIO + " caracteres como minimo");
			devolver = false;
		} else {
			labelErrorNombreUsuario.setValue("");
		}
		// valido que el campo de contrasenia no este vacio
		if (textBoxContrasenia.getText().isEmpty() || textBoxContrasenia.getText().length() < LONGITUD_MINIMA_CONTRASENIA) {
			labelErrorContrasenia.setValue("La contraseña debe tener " + LONGITUD_MINIMA_CONTRASENIA + " caracteres como minimo");
			devolver = false;
		} else {
			labelErrorContrasenia.setValue("");
		}
		// valido que el campo de contrasenia, coincida con el campo de contrasenia repetida
		if (!textBoxContrasenia.getText().equals(textBoxContraseniaRepetida.getText())) {
			labelErrorContraseniaRepetida.setValue("Asegurese de que las contraseñas coinciden");
			devolver = false;
		} else {
			labelErrorContraseniaRepetida.setValue("");
		}
		// valido que el campo nombre no este vacio
		if (textBoxNombre.getText().isEmpty()) {
			labelErrorNombre.setValue("Asegurese de ingresar su nombre");
			devolver = false;
		} else {
			labelErrorNombre.setValue("");
		}
		// valido que el campo apellido no este vacio
		if (textBoxApellido.getText().isEmpty()) {
			labelErrorApellido.setValue("Asegurese de ingresar su apellido");
			devolver = false;
		} else {
			labelErrorApellido.setValue("");
		}
		// valido que halla elegido tipo de documento
		if (comboboxTipoDocumento.getSelectedIndex() < 0) {
			labelErrorTipoDocumento.setValue("Asegurese de ingresar un tipo de documento");
			devolver = false;
		} else {
			labelErrorTipoDocumento.setValue("");
		}
		// valido que el campo numero de documento no sea vacio
		if (textBoxNumeroDocumento.getText().isEmpty()) {
			labelErrorNumeroDocumento.setValue("Asegurese de ingresar su numero de documento");
			devolver = false;
		} else {
			labelErrorNumeroDocumento.setValue("");
		}
		// valido que el mail no sea vacio y que este escrito como corresponde
		if (textBoxMail.getText().isEmpty() || !textBoxMail.getText().matches(".+@.+\\.[a-z]+")) {
			labelErrorMail.setValue("Asegurese de ingresar un mail valido");
			devolver = false;
		} else {
			labelErrorMail.setValue("");
		}
		// si el mail alternativo no es vacio, valido que este escrito como corresponde
		if (!textBoxMailAlternativo.getText().isEmpty()) {
			if (!textBoxMailAlternativo.getText().matches(".+@.+\\.[a-z]+")) {
				labelErrorMailAlternativo.setValue("Asegurese de ingresar un mail valido");
				devolver = false;
			} else {
				labelErrorMailAlternativo.setValue("");
			}
		} else {
			labelErrorMailAlternativo.setValue("");
		}

		if (comboBoxLocalidadResidencia.getSelectedIndex() >= 0 || 
				!textBoxCalle.getText().isEmpty() ||
				!textBoxAltura.getText().isEmpty()) {
			// si estoy aca, es porque ingresaron algun dato de domicilio
			// ver que onda
		}


		return devolver; // para validar todo "de un saque"
	}
	
	/**
	 * Construye el usuario
	 * @return usuario construido
	 */
	private Usuario construirUsuario() {
		Usuario usuarioConstruido = new Usuario();
		
		usuarioConstruido.setNombre(textBoxNombre.getText());
		usuarioConstruido.setApellido(textBoxApellido.getText());
		usuarioConstruido.setMail(textBoxMail.getText());
		String mailAlternativo = textBoxMailAlternativo.getText();
		
		if (!mailAlternativo.isEmpty()) {
			usuarioConstruido.setMailAlternativo(mailAlternativo);
		}
		
		String telefono = textBoxTelefonoContacto.getText();
		if (!telefono.isEmpty()) {
			usuarioConstruido.setTelefono(telefono);
		}
		
		if (comboBoxNacionalidad.getSelectedIndex() >= 0) {
			usuarioConstruido.setNacionalidad(listaNacionalidades.get(comboBoxNacionalidad.getSelectedIndex()));
		}
		
		return usuarioConstruido;
	}
	
	/**
	 * Construye el documento
	 * @return documento construido
	 */
	private Documento construirDocumento() {
		Documento documento = new Documento();
		documento.setNumero(textBoxNumeroDocumento.getText());
		documento.setTipoDocumento(listaTiposDocumento.get(comboboxTipoDocumento.getSelectedIndex()));
		return documento;
	}
	
	/**
	 * Construye el domicilio
	 * @return el domicilio creado o null si el usuario no ingreso los datos minimos de domicilio
	 * que serian localidad, calle y altura
	 */
	private Domicilio construirDomicilio() {
		if (comboBoxLocalidadResidencia.getSelectedIndex() >= 0 && 
				!textBoxCalle.getText().isEmpty() &&
				!textBoxAltura.getText().isEmpty()) {
			// si estoy aca, es porque ingresaron los datos de domicilio minimos!
			// ver que onda
			Domicilio domicilio = new Domicilio();
			domicilio.setLocalidad(listaLocalidades.get(comboBoxLocalidadResidencia.getSelectedIndex()));
			domicilio.setCalle(textBoxCalle.getText());
			domicilio.setNumero(textBoxAltura.getText());
			domicilio.setDepto(textBoxDepto.getText());
			domicilio.setPiso(textBoxPiso.getText());
			return domicilio;
		}
		return null;
	}
	
	/**
	 * construye el usuario registrado, sin setearle el usuario
	 * @return usuario registrado construido
	 */
	private UsuarioRegistrado construirUsuarioRegistrado() {
		UsuarioRegistrado usuarioRegistradoConstruido = new UsuarioRegistrado();
		usuarioRegistradoConstruido.setNick(textBoxNombreUsuario.getText());
		usuarioRegistradoConstruido.setContrasenia(textBoxContrasenia.getText());
		usuarioRegistradoConstruido.setContraseniaRegenerada(false);
		usuarioRegistradoConstruido.setRol(0);
		
		return usuarioRegistradoConstruido;
	}

	@Listen("onClick = #botonRegistrarse")
	public void registrarse() {
		boolean valida = validar();
		if (valida) {
			labelErroresAlUsuario.setValue("");
			
			Usuario usuario = construirUsuario();
			UsuarioRegistrado usuarioRegistrado = construirUsuarioRegistrado();
			Domicilio domicilio = construirDomicilio();
			Documento documento = construirDocumento();
			// faltaria institucion y ocupacion
			
			try {
				usuarioService.crearUsuario(usuario, usuarioRegistrado, documento, domicilio);
			} catch(DataIntegrityViolationException e) {
				String error = parserExcepciones.transformar(e.getMessage());
				Messagebox.show("ERROR: " + error);
				System.out.println(e.toString());
				return;
			} 
			Messagebox.show("Se creo el usuario con EXITO, en breve recibirá un mail con los datos de su cuenta");
		} else {
			labelErroresAlUsuario.setValue("Error: verifique los campos solicitados");
		}
	}

}
